﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Miao
{
    /// <summary>
    /// 轮盘赌算法的抽象实现
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Roulette<T> : IEnumerable<KeyValuePair<T, float>>
    {
        /// <summary>
        /// 当前轮盘中的总点数
        /// </summary>
        public float totalPoints { get; protected set; }
        /// <summary>
        /// 当前轮盘中的赌注数
        /// </summary>
        public int betsNumber { get { return betsPair.Count; } }

        private readonly List<KeyValuePair<T, float>> betsPair;

        public Roulette(IList<T> bets, IList<float> points)
        {
            int betsNumber = bets.Count;
            if (betsNumber != points.Count) throw new Exception($"{nameof(Roulette<T>)}: 赌注和点数的数量必须一致!");
            betsPair = new List<KeyValuePair<T, float>>(betsNumber);
            for (int i = 0; i < betsNumber; i++)
            {
                float point = points[i];
                betsPair.Add(new KeyValuePair<T, float>(bets[i], point));
                totalPoints += point;
            }
        }
        public Roulette(Dictionary<T, float> dictionary)
        {
            int count = dictionary.Count;
            betsPair = new List<KeyValuePair<T, float>>(count);
            int index = 0;
            foreach (var pair in dictionary)
            {
                totalPoints += pair.Value;
                betsPair[index++] = pair;
            }
        }
        protected Roulette(Roulette<T> otherRoulette)
        {
            List<KeyValuePair<T, float>> betsPairOfOtherRoulette = otherRoulette.betsPair;
            int count = betsPairOfOtherRoulette.Count;
            betsPair = new List<KeyValuePair<T, float>>(count);
            for (int i = 0; i < count; i++) betsPair[i] = betsPairOfOtherRoulette[i];
        }
        public Roulette(int defaultCapacity)
        {
            betsPair = new List<KeyValuePair<T, float>>(defaultCapacity);
        }
        public Roulette()
        {
            betsPair = new List<KeyValuePair<T, float>>();
        }

        /// <summary>
        /// 获取一个赌注
        /// </summary>
        /// <returns>在轮盘中基于轮盘赌策略运算后的赌注</returns>
        public T Start()
        {
            if (betsPair.Count == 0) throw new Exception("轮盘中没有任何赌注!");
            float randomPoint = totalPoints * RandomW.RandomFloat01();
            float accumulatePoint = 0;
            foreach (var pair in betsPair)
            {
                accumulatePoint += pair.Value;
                if (accumulatePoint >= randomPoint) return pair.Key;
            }
            return default;
        }
        /// <summary>
        /// 添加赌注
        /// </summary>
        /// <param name="bet">赌注</param>
        /// <param name="point">赌注对应的点数</param>
        public void AddBet(T bet, float point)
        {
            betsPair.Add(new KeyValuePair<T, float>(bet, point));
            totalPoints += point;
        }
        /// <summary>
        /// 移除赌注
        /// </summary>
        /// <param name="bet"></param>
        /// <returns></returns>
        public bool RemoveBet(T bet)
        {
            KeyValuePair<T, float> pair = default;
            bool betExist = false;
            foreach (var betpair in betsPair)
            {
                if (betpair.Key.Equals(bet))
                {
                    pair = betpair;
                    betExist = true;
                    break;
                }
            }
            if (!betExist) return false;
            betsPair.Remove(pair);
            totalPoints -= pair.Value;
            return true;
        }
        public void RemoveBetAt(int index)//移除指定索引的赌注
        {
            if (index < 0 || index >= betsPair.Count) throw new Exception("错误,索引越界!");
            betsPair.RemoveAt(index);
        }
        public Roulette<T> ReturnNewRouletteRemovedBet(T bet)//移除一个赌注并返回新的轮盘
        {
            KeyValuePair<T, float> pair = default;
            bool exist = false;
            foreach (var betPair in betsPair)
            {
                if (betPair.Key.Equals(bet))
                {
                    pair = betPair;
                    exist = true;
                    break;
                }
            }
            if (!exist) return null;
            Roulette<T> newRoulette = new Roulette<T>(this);
            newRoulette.betsPair.Remove(pair);
            newRoulette.totalPoints -= pair.Value;
            return newRoulette;
        }

        IEnumerator<KeyValuePair<T, float>> IEnumerable<KeyValuePair<T, float>>.GetEnumerator()
        {
            return betsPair.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return betsPair.GetEnumerator();
        }
    }
}